package org.tinygroup.datasource.jmeter;

import org.apache.commons.dbcp.BasicDataSource;
import org.tinygroup.dbcluster.algorithm.SingleKeyModuloDatabaseShardingAlgorithm;
import org.tinygroup.dbcluster.algorithm.table.NoneTableShardingAlgorithm;
import org.tinygroup.dbcluster.base.*;
import org.tinygroup.dbcluster.jdbc.DbclusterDataSource;
import org.tinygroup.dbcluster.strategy.database.DatabaseShardingStrategy;
import org.tinygroup.dbcluster.strategy.table.TableShardingStrategy;
import org.tinygroup.logger.Logger;
import org.tinygroup.logger.LoggerFactory;
import performance.ResourceLoadUtil;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.util.*;

/**
 * Created by wangwy on 2017/1/17.
 */
public class DataSourceFactory {
    protected static Logger logger = LoggerFactory.getLogger(DataSourceFactory.class);

    private static Properties prop = new Properties();

    //dbcluster数据源
    private static DbclusterDataSource shardingDataSource;

    private static final Map<String, DataSource> DATA_SOURCES = new HashMap<String, DataSource>();

    private static void init(){
        InputStream in = ResourceLoadUtil.getLocationInputStream("jdbc-ds.properties");

        try {
            prop.load(in);
        } catch (IOException e) {
            logger.errorMessage(e.getMessage(),e);
        }
    }

    protected static final Map<String, DataSource> createDataSourceMap(
            final String dataSourceName) {
        Map<String, DataSource> result = new HashMap<String, DataSource>();
        for (int i=0;i<2;i++) {
            result.put(String.format(dataSourceName, i),
                    createDataSource(String.valueOf(i)));
        }
        return result;
    }

    public static DataSource getDbclusterDataSource(){
        if (null != shardingDataSource) {
            return shardingDataSource;
        }
        init();
        ShardDbRule dataSourceRule = new ShardDbRule(createDataSourceMap("dataSource_%s"),"dataSource_0");
        ShardTableRule tableRule1 = ShardTableRule.builder("score").actualTables(Arrays.asList(
                "score")).dataSourceRule(dataSourceRule).build();
        ShardTableRule tableRule2 = ShardTableRule.builder("t_user").actualTables(Arrays.asList(
                "t_user")).dataSourceRule(dataSourceRule).build();
        ShardTableRule tableRule3 = ShardTableRule.builder("t_custom").dataSourceRule(dataSourceRule).build();
        ShardTableRule tableRule4 = ShardTableRule.builder("t_order").dataSourceRule(dataSourceRule).build();
        ShardRule shardingRule = new ShardRule(dataSourceRule, Arrays.asList(tableRule1, tableRule2,tableRule3,tableRule4),
                Collections.singletonList(new BindingTableRule(Arrays.asList(tableRule3, tableRule4))),
                new DatabaseShardingStrategy("id", new SingleKeyModuloDatabaseShardingAlgorithm()),
                new TableShardingStrategy("id", new NoneTableShardingAlgorithm()));
        shardingDataSource= new DbclusterDataSource(new AppRule(shardingRule));
        return shardingDataSource;
    }

    private static DataSource createDataSource(final String datasourcekey) {
        if (DATA_SOURCES.containsKey(datasourcekey)) {
            return DATA_SOURCES.get(datasourcekey);
        }
        BasicDataSource result = new BasicDataSource();

        String url = prop.getProperty("url"+datasourcekey).trim();
        String password = prop.getProperty("password"+datasourcekey).trim();
        String user=prop.getProperty("user"+datasourcekey).trim();
        String driver=prop.getProperty("driver"+datasourcekey).trim();

        result.setDriverClassName(driver);
        result.setUrl(url);
        result.setUsername(user);
        result.setPassword(password);
        result.setTimeBetweenEvictionRunsMillis(1000);
        result.setMinEvictableIdleTimeMillis(1000);
        result.setMaxIdle(32);
        result.setMinIdle(5);
        result.setNumTestsPerEvictionRun(50);
        result.setInitialSize(5);

        DATA_SOURCES.put(datasourcekey, result);
        return result;
    }

    public static void closeDataSources() {
        for(String key:DATA_SOURCES.keySet()){
            BasicDataSource dataSource = (BasicDataSource) DATA_SOURCES.get(key);
            if(!dataSource.isClosed()) {
                try {
                    dataSource.close();
                } catch (SQLException e) {
                    logger.warn("关闭失败！",e);
                }
            }
        }
    }

}
